<template>
  <view
    class="mxp-tags"
    :class="newClass"
    :hoverClass="!disabled && !loading ? 'hover-class' : ''"
    :hoverStartTime="0"
    :hoverStayTime="0"
    :style="[newButtonStyle, cusStyle]"
    :hoverStopPropagation="hoverStopPropagation"
    @click="clickHandler"
  >
    <mxp-icon
      v-if="loading"
      name="jiazai"
      :spin="true"
      :color="newIconColor"
      :size="newIconSize"
      :cusStyle="{ marginRight: loadingText || loadingText === undefined ? newIconMargin : '0px' }"
    ></mxp-icon>
    <slot v-if="!loading" name="left">
      <mxp-icon-image v-if="leftIcon" :icon="leftIcon" :size="newIconSize" :cusStyle="{ marginRight: newIconMargin }"></mxp-icon-image>
    </slot>
    <slot>
      <text class="text" :style="[newTextStyle, textStyle]">{{ loading && loadingText !== undefined ? loadingText : text }}</text>
    </slot>
    <slot name="right">
      <mxp-icon-image v-if="rightIcon" :icon="rightIcon" :size="newIconSize" :cusStyle="{ marginLeft: newIconMargin }"></mxp-icon-image>
    </slot>
    <mxp-icon
      v-if="closable && newCloseLoading"
      key="mxp-icon-2"
      name="jiazai"
      :spin="true"
      :color="newIconColor"
      :size="newIconSize"
      :cusStyle="{ marginLeft: loadingText || loadingText === undefined ? newIconMargin : '0px' }"
    ></mxp-icon>
    <view v-if="!newCloseLoading && closable" class="close-box" @click.stop.prevent="onClose">
      <mxp-icon name="guanbi" :size="newIconSize" :color="newIconColor" :cusStyle="{ marginLeft: newIconMargin, transform: 'scale(0.8)' }"></mxp-icon>
    </view>
  </view>
</template>

<script setup lang="ts">
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import { type CSSProperties, type PropType, computed, ref, watch } from 'vue';
  import type { $AllColorStr, $ButtonSize, $ColorType, $SizeUnitArr4Str, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import MxpIcon from '@/mxp-ui/mxp-icon/mxp-icon.vue';
  import MxpIconImage from '@/mxp-ui/mxp-icon-image/mxp-icon-image.vue';
  import { defThemeColor } from '../mxp-tool/theme/theme';
  import { isDarkColorStorage, lightenDarkenColorStorage } from '../mxp-tool/utils/color';

  defineOptions({
    name: 'mxp-tags',
  });

  const props = defineProps({
    /**
     * 按钮大小
     * @param max - 最大的
     * @param large - 较大的
     * @param middle - 适中的
     * @param small - 较小的
     * @param min - 最小的
     */
    size: { type: String as PropType<$ButtonSize>, default: 'small' },
    /** 按钮的预置样式支持 "error" | "info" | "primary" | "success" | "warning" 和自定义的颜色（支持渐变色） 如#ff0000 */
    background: { type: String as PropType<$AllColorStr | $ColorType | `linear-gradient(${string})`>, default: 'primary' },
    /** 按钮形状，circle(两边为半圆)，square(带圆角) */
    radius: { type: String as PropType<$SizeUnitArr4Str | 'circle' | 'square'>, default: 'square' },
    /** 是否粗体 */
    bold: { type: Boolean, default: false },
    /** 按钮是否镂空 */
    plain: { type: Boolean, default: false },
    /** 镂空时是否有背景色 */
    plainBackground: { type: Boolean, default: true },
    /** 镂空时是否有边框 */
    plainBorder: { type: Boolean, default: true },
    /** 文本样式 */
    textStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 是否禁用状态 */
    disabled: { type: Boolean, default: false },
    /** 是否为加载中 */
    loading: { type: Boolean, default: false },
    /** 是否为加载中 */
    loadingText: { type: [String, Number], default: undefined },
    /** 是否为关闭中 */
    closeLoading: { type: Boolean, default: false },
    /** 指定是否阻止本节点的祖先节点出现点击态，微信小程序有效 */
    hoverStopPropagation: { type: Boolean, default: true },
    /** 按钮的文本 */
    text: { type: [String, Number], default: '' },
    /** 是否为纯文本的标签 */
    isTextTags: { type: Boolean, default: false },
    /** 按钮颜色 */
    color: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 图标大小 */
    iconSize: { type: String as PropType<$SizeUnitStr>, default: undefined },
    /** 图标颜色(默认颜色与文字颜色相同) */
    loadingIconColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 左侧图标路径 */
    leftIcon: { type: String, default: undefined },
    /** 右侧图标路径 */
    rightIcon: { type: String, default: undefined },
    /** 图标与文字的间距 */
    iconMargin: { type: String as PropType<$SizeUnitStr>, default: undefined },
    /** 文字大小 */
    fontSize: { type: String as PropType<$SizeUnitStr>, default: undefined },
    /** 按钮的宽度 */
    width: { type: String as PropType<$SizeUnitStr>, default: undefined },
    /** 按钮的高度 */
    height: { type: String as PropType<$SizeUnitStr>, default: undefined },
    /** 是否显示关闭按钮 */
    closable: { type: Boolean, default: true },
    /** 关闭前执行的函数(需要返回 boolean 或者 Promise<boolean>) */
    beforeClose: { type: [Function, undefined] as PropType<(() => Promise<boolean> | boolean) | undefined>, default: undefined },
    /** 按下和禁止点击的背景透明度,默认为0.8 */
    opacity: { type: Number, default: 0.8 },
    ...publicStyeProps, // 混淆props共有参数
  });
  defineSlots<{
    /** 左边 */
    left: () => void;
    /** 主体 */
    default: () => void;
    /** 右边 */
    right: () => void;
  }>();

  const emits = defineEmits<{
    (e: 'update:closeLoading', state: boolean): void;
    (e: 'click'): void;
    (e: 'close'): void;
  }>();

  const sizeObj: Record<
    $ButtonSize,
    { h: $SizeUnitStr; iconSize: $SizeUnitStr; fontSize: $SizeUnitStr; round: $SizeUnitStr; iconMargin: $SizeUnitStr; padding: $SizeUnitArr4Str }
  > = {
    min: { h: '18px', iconSize: '10px', fontSize: '10px', round: '4px', iconMargin: '2px', padding: '2px 8px' },
    small: { h: '20px', iconSize: '12px', fontSize: '12px', round: '4px', iconMargin: '4px', padding: '3px 10px' },
    middle: { h: '22px', iconSize: '13px', fontSize: '14px', round: '6px', iconMargin: '6px', padding: '4px 14px' },
    large: { h: '24px', iconSize: '16px', fontSize: '16px', round: '6px', iconMargin: '8px', padding: '5px 16px' },
    max: { h: '24px', iconSize: '18px', fontSize: '18px', round: '8px', iconMargin: '10px', padding: '6px 18px' },
  };
  const newIconMargin = computed<$SizeUnitStr>(() => {
    return props.iconMargin ? props.iconMargin : props.size in sizeObj ? sizeObj[props.size].iconMargin : sizeObj.middle.iconMargin;
  });

  const newCloseLoading = ref(props.closeLoading);
  watch(
    () => props.closeLoading,
    (val) => {
      newCloseLoading.value = val;
    }
  );
  const newClass = computed(() => {
    const cla: string[] = [props.cusClass, props.isTextTags ? 'text' : props.plain ? 'plain' : 'bg'];
    (props.disabled || props.loading) && cla.push('hover-class');
    return cla;
  });

  const newButtonStyle = computed<CSSProperties>(() => {
    const obj: CSSProperties = {};

    if (!props.isTextTags) {
      if (props.width) {
        obj.width = props.width;
      } else {
        obj.display = 'inline-flex';
        obj.width = 'auto';
      }
      obj.padding = sizeObj[props.size].padding;

      obj.height = props.height ? props.height : sizeObj[props.size].h;

      if (props.radius === 'circle') {
        obj.borderRadius = '999999px';
      } else if (props.radius === 'square') {
        obj.borderRadius = `${sizeObj[props.size].round}`;
      } else {
        obj.borderRadius = props.radius;
      }
    } else {
      obj.border = 'none';
      obj.borderRadius = '0px';
      obj.display = 'inline-flex';
      obj.width = 'auto';
    }

    obj['--opacity'] = props.opacity;

    /** 背景 */
    const bg = props.background in defThemeColor.value ? defThemeColor.value[props.background as $ColorType] : props.background;
    /** 点击时的背景 */
    const hbg = lightenDarkenColorStorage(bg as string, 0.9) || bg;

    if (props.isTextTags) {
      obj['--text-background'] = 'rgba(0,0,0,0)';
      obj['--text-border-color'] = 'rgba(0,0,0,0)';
      obj['--hover-background'] = 'rgba(0,0,0,0)';
      obj['--hover-border-color'] = 'rgba(0,0,0,0)';
      obj['--text-color'] = props.color ? props.color : bg;
      obj['--hover-color'] = lightenDarkenColorStorage(props.color ? props.color : bg, 0.95) || props.color || bg;
    } else if (props.plain) {
      obj['--plain-background'] = props.plainBackground ? lightenDarkenColorStorage(bg as string, 0.1) || 'rgba(0,0,0,0)' : 'rgba(0,0,0,0)';
      obj['--plain-border-color'] = props.plainBorder ? bg : obj['--plain-background'];
      obj['--hover-background'] = props.plainBackground
        ? lightenDarkenColorStorage(obj['--plain-background'] as string, 0.9, 'light') || obj['--plain-background']
        : 'rgba(0,0,0,0)';
      obj['--hover-border-color'] = props.plainBorder ? lightenDarkenColorStorage(hbg || '', 0.8) || bg : obj['--hover-background'];
      obj['--plain-color'] = props.color ? props.color : bg;
      obj['--hover-color'] = lightenDarkenColorStorage(props.color ? props.color : hbg, 0.95) || props.color || hbg;
    } else {
      obj['--border-background'] = bg;
      obj['--background'] = bg;
      obj['--hover-background'] = hbg;
      obj['--hover-border-color'] = hbg;
      obj['--color'] = props.color
        ? props.color
        : props.background in defThemeColor.value
          ? defThemeColor.value.textLight
          : isDarkColorStorage(props.background)
            ? defThemeColor.value.text
            : defThemeColor.value.textLight;
      obj['--hover-color'] = props.color ? props.color : lightenDarkenColorStorage(obj['--color'] as string, 0.95) || obj['--color'];
    }

    return obj;
  });

  /** 最终 文本 的样式 */
  const newTextStyle = computed<CSSProperties>(() => {
    const obj: CSSProperties = { fontWeight: props.bold ? 'bold' : 'normal' };
    obj.fontSize = props.fontSize ? props.fontSize : props.size in sizeObj ? sizeObj[props.size].fontSize : props.iconSize ? props.iconSize : `14px`;
    obj.lineHeight = obj.fontSize;
    return obj;
  });

  /** 最终 icon 的大小 */
  const newIconSize = computed<$SizeUnitStr>(() => {
    return props.iconSize ? props.iconSize : props.size in sizeObj ? sizeObj[props.size].iconSize : props.fontSize ? props.fontSize : '14px';
  });
  /** 最终 icon 的颜色 */
  const newIconColor = computed<$AllColorStr>(() => props.loadingIconColor || (newButtonStyle.value['--hover-color'] as $AllColorStr));

  /** 点击事件 */
  function clickHandler() {
    if (!props.disabled && !props.loading) {
      emits('click');
    }
  }
  /** 点击关闭 */
  async function onClose() {
    if (typeof props.beforeClose === 'function') {
      try {
        emits('update:closeLoading', true);
        newCloseLoading.value = true;
        const state = await props.beforeClose();
        newCloseLoading.value = false;
        emits('update:closeLoading', false);
        state && emits('close');
      } catch (error) {
        emits('update:closeLoading', false);
        newCloseLoading.value = false;
      }
    } else {
      emits('close');
    }
  }
</script>

<style scoped lang="scss">
  .mxp-tags {
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    justify-content: center;
    margin-right: 0;
    margin-left: 0;
    background-color: transparent;
  }

  .text {
    background: var(--text-background);
    border: 1px solid var(--text-border);

    .text {
      color: var(--text-color);
    }
  }

  .bg {
    background: var(--background);
    border: 1px solid var(--border-background);

    .text {
      color: var(--color);
    }
  }

  .plain {
    background: var(--plain-background);
    border: 1px solid var(--plain-border-color);

    .text {
      color: var(--plain-color);
    }
  }

  .hover-class {
    background: var(--hover-background) !important;
    border: 1px solid var(--hover-border-color);
    opacity: var(--opacity);

    .text {
      color: var(--hover-color);
    }
  }

  .close-box {
    padding: 3px 0;
  }
</style>
